home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / msdos / viewers / hv12 / src / jrdtarga.c < prev    next >
C/C++ Source or Header  |  1992-04-26  |  12KB  |  437 lines

  1. /*
  2.  * jrdtarga.c
  3.  *
  4.  * Copyright (C) 1991, 1992, Thomas G. Lane.
  5.  * This file is part of the Independent JPEG Group's software.
  6.  * For conditions of distribution and use, see the accompanying README file.
  7.  *
  8.  * This file contains routines to read input images in Targa format.
  9.  *
  10.  * These routines may need modification for non-Unix environments or
  11.  * specialized applications.  As they stand, they assume input from
  12.  * an ordinary stdio stream.  They further assume that reading begins
  13.  * at the start of the file; input_init may need work if the
  14.  * user interface has already read some data (e.g., to determine that
  15.  * the file is indeed Targa format).
  16.  *
  17.  * These routines are invoked via the methods get_input_row
  18.  * and input_init/term.
  19.  *
  20.  * Based on code contributed by Lee Daniel Crocker.
  21.  */
  22.  
  23. #include "jinclude.h"
  24. #include "hicolor.h"
  25.  
  26. #ifdef TARGA_SUPPORTED
  27.  
  28.  
  29. /* Macros to deal with unsigned chars as efficiently as compiler allows */
  30.  
  31. #ifdef HAVE_UNSIGNED_CHAR
  32. typedef unsigned char U_CHAR;
  33. #define UCH(x)    ((int) (x))
  34. #else /* !HAVE_UNSIGNED_CHAR */
  35. #ifdef CHAR_IS_UNSIGNED
  36. typedef char U_CHAR;
  37. #define UCH(x)    ((int) (x))
  38. #else
  39. typedef char U_CHAR;
  40. #define UCH(x)    ((int) (x) & 0xFF)
  41. #endif
  42. #endif /* HAVE_UNSIGNED_CHAR */
  43.  
  44.  
  45. #define    ReadOK(file,buffer,len)    (JFREAD(file,buffer,len) == ((size_t) (len)))
  46.  
  47.  
  48. static JSAMPARRAY colormap;    /* Targa colormap (converted to my format) */
  49.  
  50. /*
  51. static big_sarray_ptr whole_image; */
  52.                 /* Needed if funny input row order */
  53. static long current_row;    /* Current logical row number to read */
  54.  
  55. /* Pointer to routine to extract next Targa pixel from input file */
  56. static void (*read_pixel) PP((compress_info_ptr cinfo));
  57.  
  58. /* Result of read_pixel is delivered here: */
  59. static U_CHAR tga_pixel[4];
  60.  
  61. static int pixel_size;        /* Bytes per Targa pixel (1 to 4) */
  62.  
  63. /* State info for reading RLE-coded pixels; both counts must be init to 0 */
  64. static int block_count;        /* # of pixels remaining in RLE block */
  65. static int dup_pixel_count;    /* # of times to duplicate previous pixel */
  66.  
  67. /* This saves the correct pixel-row-expansion method for preload_image */
  68. static void (*get_pixel_row) PP((compress_info_ptr cinfo,
  69.                  JSAMPARRAY pixel_row));
  70.  
  71.  
  72. /* For expanding 5-bit pixel values to 8-bit with best rounding */
  73.  
  74. static const UINT8 c5to8bits[32] = {
  75.     0,   8,  16,  24,  32,  41,  49,  57,
  76.    65,  74,  82,  90,  98, 106, 115, 123,
  77.   131, 139, 148, 156, 164, 172, 180, 189,
  78.   197, 205, 213, 222, 230, 238, 246, 255
  79. };
  80.  
  81.  
  82.  
  83. LOCAL int
  84. read_byte (compress_info_ptr cinfo)
  85. /* Read next byte from Targa file */
  86. {
  87.   register FILE *infile = cinfo->input_file;
  88.   register int c;
  89.  
  90.   if ((c = getc(infile)) == EOF)
  91.     ERREXIT(cinfo->emethods, "Premature EOF in Targa file");
  92.   return c;
  93. }
  94.  
  95.  
  96. LOCAL void
  97. read_colormap (compress_info_ptr cinfo, int cmaplen, int mapentrysize)
  98. /* Read the colormap from a Targa file */
  99. {
  100.   int i;
  101.  
  102.   /* Presently only handles 24-bit BGR format */
  103.   if (mapentrysize != 24)
  104.     ERREXIT(cinfo->emethods, "Unsupported Targa colormap format");
  105.  
  106.   for (i = 0; i < cmaplen; i++) {
  107.     colormap[2][i] = (JSAMPLE) read_byte(cinfo);
  108.     colormap[1][i] = (JSAMPLE) read_byte(cinfo);
  109.     colormap[0][i] = (JSAMPLE) read_byte(cinfo);
  110.   }
  111. }
  112.  
  113.  
  114. /*
  115.  * read_pixel methods: get a single pixel from Targa file into tga_pixel[]
  116.  */
  117.  
  118. LOCAL void
  119. read_non_rle_pixel (compress_info_ptr cinfo)
  120. /* Read one Targa pixel from the input file; no RLE expansion */
  121. {
  122.   register FILE * infile = cinfo->input_file;
  123.   register int i;
  124.  
  125.   for (i = 0; i < pixel_size; i++) {
  126.     tga_pixel[i] = (U_CHAR) getc(infile);
  127.   }
  128. }
  129.  
  130.  
  131. LOCAL void
  132. read_rle_pixel (compress_info_ptr cinfo)
  133. /* Read one Targa pixel from the input file, expanding RLE data as needed */
  134. {
  135.   register FILE * infile = cinfo->input_file;
  136.   register int i;
  137.  
  138.   /* Duplicate previously read pixel? */
  139.   if (dup_pixel_count > 0) {
  140.     dup_pixel_count--;
  141.     return;
  142.   }
  143.  
  144.   /* Time to read RLE block header? */
  145.   if (--block_count < 0) {    /* decrement pixels remaining in block */
  146.     i = read_byte(cinfo);
  147.     if (i & 0x80) {        /* Start of duplicate-pixel block? */
  148.       dup_pixel_count = i & 0x7F; /* number of duplications after this one */
  149.       block_count = 0;        /* then read new block header */
  150.     } else {
  151.       block_count = i & 0x7F;    /* number of pixels after this one */
  152.     }
  153.   }
  154.  
  155.   /* Read next pixel */
  156.   for (i = 0; i < pixel_size; i++) {
  157.     tga_pixel[i] = (U_CHAR) getc(infile);
  158.   }
  159. }
  160.  
  161.  
  162. /*
  163.  * Read one row of pixels.
  164.  *
  165.  * We provide several different versions depending on input file format.
  166.  */
  167.  
  168.  
  169. METHODDEF void
  170. get_8bit_gray_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
  171. /* This version is for reading 8-bit grayscale pixels */
  172. {
  173.   register JSAMPROW ptr0,ptr1,ptr2;
  174.   register long col;
  175.  
  176. /* ## I added ptr1 and ptr2 to not have to deal with grey stuff */
  177. /*    separately. Mohammad */
  178.  
  179.   ptr0 = pixel_row[0];
  180.   ptr1 = pixel_row[1];
  181.   ptr2 = pixel_row[2];
  182.   for (col = cinfo->image_width; col > 0; col--) {
  183.     (*read_pixel) (cinfo);    /* Load next pixel into tga_pixel */
  184.     *ptr0++ = (JSAMPLE) UCH(tga_pixel[0]);
  185.     *ptr1++ = (JSAMPLE) UCH(tga_pixel[0]);
  186.     *ptr2++ = (JSAMPLE) UCH(tga_pixel[0]);
  187.   }
  188. }
  189.  
  190. METHODDEF void
  191. get_8bit_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
  192. /* This version is for reading 8-bit colormap indexes */
  193. {
  194.   register int t;
  195.   register JSAMPROW ptr0, ptr1, ptr2;
  196.   register long col;
  197.   
  198.   ptr0 = pixel_row[0];
  199.   ptr1 = pixel_row[1];
  200.   ptr2 = pixel_row[2];
  201.   for (col = cinfo->image_width; col > 0; col--) {
  202.     (*read_pixel) (cinfo);    /* Load next pixel into tga_pixel */
  203.     t = UCH(tga_pixel[0]);
  204.     *ptr0++ = colormap[0][t];
  205.     *ptr1++ = colormap[1][t];
  206.     *ptr2++ = colormap[2][t];
  207.   }
  208. }
  209.  
  210. METHODDEF void
  211. get_16bit_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
  212. /* This version is for reading 16-bit pixels */
  213. {
  214.   register int t;
  215.   register JSAMPROW ptr0, ptr1, ptr2;
  216.   register long col;
  217.   
  218.   ptr0 = pixel_row[0];
  219.   ptr1 = pixel_row[1];
  220.   ptr2 = pixel_row[2];
  221.   for (col = cinfo->image_width; col > 0; col--) {
  222.     (*read_pixel) (cinfo);    /* Load next pixel into tga_pixel */
  223.     t = UCH(tga_pixel[0]);
  224.     t += UCH(tga_pixel[1]) << 8;
  225.     /* We expand 5 bit data to 8 bit sample width.
  226.      * The format of the 16-bit (LSB first) input word is
  227.      *     xRRRRRGGGGGBBBBB
  228.      */
  229.     *ptr2++ = (JSAMPLE) c5to8bits[t & 0x1F];
  230.     t >>= 5;
  231.     *ptr1++ = (JSAMPLE) c5to8bits[t & 0x1F];
  232.     t >>= 5;
  233.     *ptr0++ = (JSAMPLE) c5to8bits[t & 0x1F];
  234.   }
  235. }
  236.  
  237. METHODDEF void
  238. get_24bit_row (compress_info_ptr cinfo, JSAMPARRAY pixel_row)
  239. /* This version is for reading 24-bit pixels */
  240. {
  241.   register JSAMPROW ptr0, ptr1, ptr2;
  242.   register long col;
  243.  
  244.   ptr0 = pixel_row[0];
  245.   ptr1 = pixel_row[1];
  246.   ptr2 = pixel_row[2];
  247.   for (col = cinfo->image_width; col > 0; col--) {
  248.     (*read_pixel) (cinfo);    /* Load next pixel into tga_pixel */
  249.     *ptr0++ = (JSAMPLE) UCH(tga_pixel[2]); /* convert BGR to RGB order */
  250.     *ptr1++ = (JSAMPLE) UCH(tga_pixel[1]);
  251.     *ptr2++ = (JSAMPLE) UCH(tga_pixel[0]);
  252.   }
  253. }
  254.  
  255. /*
  256.  * Targa also defines a 32-bit pixel format with order B,G,R,A.
  257.  * We presently ignore the attribute byte, so the code for reading
  258.  * these pixels is identical to the 24-bit routine above.
  259.  * This works because the actual pixel length is only known to read_pixel.
  260.  */
  261.  
  262. #define get_32bit_row  get_24bit_row
  263.  
  264.  
  265.  
  266.  
  267. /*
  268.  * This method loads the image into whole_image during the first call on
  269.  * get_input_row.  The get_input_row pointer is then adjusted to call
  270.  * get_memory_row on subsequent calls.
  271.  */
  272. /* preload image routine deleted ## Mohammad 4/7/92 */
  273.  
  274. /*
  275.  * Read the file header; return image size and component count.
  276.  */
  277.  
  278. METHODDEF void
  279. targa_input_init(compress_info_ptr cinfo)
  280. {
  281.   U_CHAR targaheader[18];
  282.   int idlen, cmaptype, subtype, flags, interlace_type, components;
  283.   UINT16 width, height, maplen;
  284.   boolean is_bottom_up;
  285.  
  286. #define GET_2B(offset)    ((unsigned int) UCH(targaheader[offset]) + \
  287.              (((unsigned int) UCH(targaheader[offset+1])) << 8))
  288.  
  289.   if (! ReadOK(cinfo->input_file, targaheader, 18))
  290.     ERREXIT(cinfo->emethods, "Unexpected end of file");
  291.  
  292.   /* Pretend "15-bit" pixels are 16-bit --- we ignore attribute bit anyway */
  293.   if (targaheader[16] == 15)
  294.     targaheader[16] = 16;
  295.  
  296.   idlen = UCH(targaheader[0]);
  297.   cmaptype = UCH(targaheader[1]);
  298.   subtype = UCH(targaheader[2]);
  299.   maplen = GET_2B(5);
  300.   width = GET_2B(12);
  301.   height = GET_2B(14);
  302.   pixel_size = UCH(targaheader[16]) >> 3;
  303.   flags = UCH(targaheader[17]);    /* Image Descriptor byte */
  304.  
  305.   is_bottom_up = ((flags & 0x20) == 0);    /* bit 5 set => top-down */
  306.   interlace_type = flags >> 6;    /* bits 6/7 are interlace code */
  307.  
  308.   if (cmaptype > 1 ||        /* cmaptype must be 0 or 1 */
  309.       pixel_size < 1 || pixel_size > 4 ||
  310.       (UCH(targaheader[16]) & 7) != 0 || /* bits/pixel must be multiple of 8 */
  311.       interlace_type != 0)    /* currently don't allow interlaced image */
  312.     ERREXIT(cinfo->emethods, "Invalid or unsupported Targa file");
  313.  
  314.   if (subtype > 8) {
  315.     /* It's an RLE-coded file */
  316.     read_pixel = read_rle_pixel;
  317.     block_count = dup_pixel_count = 0;
  318.     subtype -= 8;
  319.   } else {
  320.     /* Non-RLE file */
  321.     read_pixel = read_non_rle_pixel;
  322.   }
  323.  
  324.   /* Now should have subtype 1, 2, or 3 */
  325.   components = 3;        /* until proven different */
  326.   cinfo->in_color_space = CS_RGB;
  327.  
  328.   switch (subtype) {
  329.   case 1:            /* colormapped image */
  330.     if (pixel_size == 1 && cmaptype == 1)
  331.       get_pixel_row = get_8bit_row;
  332.     else
  333.       ERREXIT(cinfo->emethods, "Invalid or unsupported Targa file");
  334.     break;
  335.   case 2:            /* RGB image */
  336.     switch (pixel_size) {
  337.     case 2:
  338.       get_pixel_row = get_16bit_row;
  339.       break;
  340.     case 3:
  341.       get_pixel_row = get_24bit_row;
  342.       break;
  343.     case 4:
  344.       get_pixel_row = get_32bit_row;
  345.       break;
  346.     default:
  347.       ERREXIT(cinfo->emethods, "Invalid or unsupported Targa file");
  348.       break;
  349.     }
  350.     break;
  351.   case 3:            /* Grayscale image */
  352.     components = 1;
  353.     cinfo->in_color_space = CS_GRAYSCALE;
  354.     if (pixel_size == 1)
  355.       get_pixel_row = get_8bit_gray_row;
  356.     else
  357.       ERREXIT(cinfo->emethods, "Invalid or unsupported Targa file");
  358.     break;
  359.   default:
  360.     ERREXIT(cinfo->emethods, "Invalid or unsupported Targa file");
  361.     break;
  362.   }
  363.  
  364.  
  365.   if (is_bottom_up) { /* needs complete modification ## Mohammad ,
  366.                             kludge for now*/
  367. /*
  368.     whole_image = (*cinfo->emethods->request_big_sarray)
  369.             ((long) width, (long) height * components,
  370.              (long) components);
  371.     cinfo->methods->get_input_row = preload_image;
  372. */
  373.     cinfo->total_passes=IS_BOTTOM_UP;
  374.     cinfo->methods->get_input_row = get_pixel_row;
  375.  
  376.                             /* count file reading as separate pass */
  377.   }
  378.   else {
  379. /*
  380.     whole_image = NULL;
  381. */
  382.     cinfo->methods->get_input_row = get_pixel_row;
  383.   }
  384.  
  385.   while (idlen--)        /* Throw away ID field */
  386.     (void) read_byte(cinfo);
  387.  
  388.   if (maplen > 0) {
  389.     if (maplen > 256 || GET_2B(3) != 0)
  390.       ERREXIT(cinfo->emethods, "Colormap too large");
  391.     /* Allocate space to store the colormap */
  392.     colormap = (*cinfo->emethods->alloc_small_sarray)
  393.             ((long) maplen, 3L);
  394.     /* and read it from the file */
  395.     read_colormap(cinfo, (int) maplen, UCH(targaheader[7]));
  396.   } else {
  397.     if (cmaptype)        /* but you promised a cmap! */
  398.       ERREXIT(cinfo->emethods, "Invalid or unsupported Targa file");
  399.     colormap = NULL;
  400.   }
  401.  
  402.   cinfo->input_components = components;
  403.   cinfo->image_width = width;
  404.   cinfo->image_height = height;
  405.   cinfo->data_precision = 8;    /* always, even if 12-bit JSAMPLEs */
  406. }
  407.  
  408.  
  409. /*
  410.  * Finish up at the end of the file.
  411.  */
  412.  
  413. METHODDEF void
  414. input_term (compress_info_ptr cinfo)
  415. {
  416.   /* no work (we let free_all release the workspace) */
  417. }
  418.  
  419.  
  420. /*
  421.  * The method selection routine for Targa format input.
  422.  * Note that this must be called by the user interface before calling
  423.  * jpeg_compress.  If multiple input formats are supported, the
  424.  * user interface is responsible for discovering the file format and
  425.  * calling the appropriate method selection routine.
  426.  */
  427.  
  428. GLOBAL void
  429. jselrtarga (compress_info_ptr cinfo)
  430. {
  431.   cinfo->methods->input_init = targa_input_init;
  432.   /* cinfo->methods->get_input_row is set by input_init */
  433.   cinfo->methods->input_term = input_term;
  434. }
  435.  
  436. #endif /* TARGA_SUPPORTED */
  437.